package com.mashibing.lock;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @author liuyno
 * @date 2021/3/8 - 23:48
 */
public class WatchAndCallback implements Watcher, AsyncCallback.StringCallback, AsyncCallback.Children2Callback, AsyncCallback.StatCallback {

    ZooKeeper zk;
    String threadName;
    String pathName;
    CountDownLatch cd = new CountDownLatch(1);

    public String getThreadName() {
        return threadName;
    }

    public void setThreadName(String threadName) {
        this.threadName = threadName;
    }

    public ZooKeeper getZk() {
        return zk;
    }

    public void setZk(ZooKeeper zk) {
        this.zk = zk;
    }

    //抢锁
    public void tryLock() {
        //创建临时节点充当锁，如果节点消失，则意味着锁被释放
        zk.create("/AppLock", threadName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, this, "caicai01");

        try {
            cd.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    //释放锁
    public void unLock() {
        try {
            zk.delete(pathName, -1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void process(WatchedEvent event) {
        switch (event.getType()) {
            case None:
                break;
            case NodeCreated:
                break;
            case NodeDeleted:
                //前面节点被删除，当前节点再次判断是否是第一个
                zk.getChildren("/", false, this, "caicai02");
                break;
            case NodeDataChanged:
                break;
            case NodeChildrenChanged:
                break;
            case DataWatchRemoved:
                break;
            case ChildWatchRemoved:
                break;
        }
    }

    //如果节点创建成功进入这个方法
    @Override
    public void processResult(int rc, String path, Object ctx, String name) {
        if (name != null) {
            //获取父路径下创建的所有临时节点，判断自己是否是第一个节点，如果是，则CountDown
            //父节点不需要被watch,每个节点只需要watch自己的前一个节点即可
            System.out.println(threadName + "create node :" + name);
            pathName = name;
            zk.getChildren("/", false, this, "caicai02");
        }
    }

    //getChildren call back
    @Override
    public void processResult(int rc, String path, Object ctx, List<String> children, Stat stat) {

        Collections.sort(children);
        int index = children.indexOf(pathName.substring(1));
        //是不是第一个
        if (index == 0) {
            //是第一个，放下门闩，让第一个拿到锁的出去干活
            System.out.println(threadName + " : I am first");
            cd.countDown();
        } else {
            //不是第一个，看自己前面的节点是否存在并watch着前一个节点的各种事件
            zk.exists("/" + children.get(index - 1), this, this, "caicai03");
        }
    }

    @Override
    public void processResult(int rc, String path, Object ctx, Stat stat) {

    }
}
